﻿using Newtonsoft.Json;
using Seagull.BarTender.Print;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ZoneLinePacking.Common;
using ZoneLinePacking.Core;
using ZoneLinePacking.Enums;
using ZoneLinePacking.Models.Entity;
using ZoneLinePacking.Models.Entity.Template;
using ZoneLinePacking.Models.PrintResult;
using ZoneLinePacking.Services.DB;

namespace ZoneLinePacking.Services.Print {

    /// <summary>
    /// 打印方法（箱码）
    /// </summary>
    public class PrinterBoxCodeService {

        private readonly IDbOperate<IFreeSqlMainContext> _mainDbOperate;

        private static object _lockObj = new object();

        //public static Engine PrinterEngine { get; private set; } = new Engine(true);

        public PrinterBoxCodeService(IDbOperate<IFreeSqlMainContext> mainDbOperate) {

            this._mainDbOperate = mainDbOperate;
        }

        /// <summary>
        /// 标签打印
        /// </summary>
        /// <param name="templatePath"></param>
        /// <param name="qrCode"></param>
        /// <param name="printParams"></param>
        /// <param name="printerName"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public async Task<bool> PrintLabel(string templatePath,string qrCode ,Dictionary<string, string> printParams, string printerName) {

            if (!File.Exists(templatePath)) {
                throw new Exception($"打印机模板文件不存在，请检查！");
            }

            var task = await Task.Factory.StartNew(() => {
                var res = false;
                LogManager.Info($"PrinterLabel Start. printerName = {printerName}，printModePath = {templatePath}");
                using (Engine _engine = new Engine(true)) {
                    _engine.Start();
                    LabelFormatDocument btFormat = _engine.Documents.Open(templatePath, printerName, printerName);
                    if (printParams != null) {
                        foreach (var item in printParams) {
                            //Reading Named Substrings,读取标签字段
                            if (btFormat.SubStrings.Any(p => p.Name == item.Key)) {
                                btFormat.SubStrings[item.Key].Value = item.Value;
                            }
                            //Print Label ,打印标签
                        }
                    }
                    LogManager.Debug($"执行打印开始,打印参数:{JsonConvert.SerializeObject(printParams)}");
                    Result result1 = btFormat.Print("PrintBoxJob_" + qrCode);
                    LogManager.Debug($"执行打印完成,rls={result1.ToString()},打印参数:{JsonConvert.SerializeObject(printParams)}");
                    //Close Label Format ,关闭标签模板
                    btFormat.Close(SaveOptions.DoNotSaveChanges);
                    // Application-specific code 
                    // Assuming the application wants to save changes, 
                    //     it can be easily done at Stop time. 
                    //btEngine.Stop(SaveOptions.DoNotSaveChanges);
                    if (result1 == Result.Failure) {
                        LogManager.Info($"打印失败");
                    }
                    if (result1 == Result.Timeout) {
                        LogManager.Info($"打印超时，请检查！");
                    }

                    res = (result1 == Result.Success);
                }
                LogManager.Info($"PrinterLabel Dispose. printerName = {printerName}，printModePath = {templatePath}");

                return res;
            });

            return task;
        }

        /// <summary>
        /// 标签预览
        /// </summary>
        /// <param name="templatePath"></param>
        /// <param name="qrCode"></param>
        /// <param name="printParams"></param>
        /// <param name="printerName"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public bool PrintLabelPreview(string templatePath, string qrCode,Dictionary<string, string> printParams, string printerName) {

            if (!File.Exists(templatePath)) {
                throw new Exception($"打印机模板文件不存在，请检查！");
            }


            var task = Task.Factory.StartNew(() => {

                LogManager.Info($"PrinterLabel Start. printerName = {printerName}，printModePath = {templatePath}");

                using (Engine _engine = new Engine(true)) {
                    _engine.Start();
                    LabelFormatDocument btFormat = _engine.Documents.Open(templatePath, printerName, printerName);
                    if (printParams != null) {
                        foreach (var item in printParams) {
                            //Reading Named Substrings,读取标签字段
                            if (btFormat.SubStrings.Any(p => p.Name == item.Key)) {
                                btFormat.SubStrings[item.Key].Value = item.Value;
                            }
                            //Print Label ,打印标签
                        }
                    }

                    _engine.Window.VisibleWindows = VisibleWindows.InteractiveDialogs;
                    var view = btFormat.PrintPreview;
                    view.ShowDialog();

                    //Close Label Format ,关闭标签模板
                    btFormat.Close(SaveOptions.DoNotSaveChanges);
                    // Application-specific code 
                    // Assuming the application wants to save changes, 
                    //     it can be easily done at Stop time. 
                    //btEngine.Stop(SaveOptions.DoNotSaveChanges);
                }

                LogManager.Info($"PrinterLabel Dispose. printerName = {printerName}，printModePath = {templatePath}");

            });

            return true;
        }

        /// <summary>
        /// 补打箱码
        /// </summary>
        /// <param name="template"></param>
        /// <param name="printerName"></param>
        /// <param name="qrCode"></param>
        /// <param name="printParams"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public bool RePrintLabel(TemplateEntity template, string printerName, string qrCode, Dictionary<string, string> printParams,int printSameLabelCount = 1) {

            if (!File.Exists(template.TemplatePath)) {
                throw new Exception($"打印机模板文件不存在，请检查！");
            }

            var task = Task.Factory.StartNew(() => {

                LogManager.Info($"PrinterLabel Start. printerName = {printerName}，printModePath = {template.TemplatePath}");

                using (Engine _engine = new Engine(true)) {
                    _engine.Start();
                    LabelFormatDocument btFormat = _engine.Documents.Open(template.TemplatePath, printerName, printerName);

                    btFormat.PrintSetup.NumberOfSerializedLabels = 1;
                    btFormat.PrintSetup.IdenticalCopiesOfLabel = printSameLabelCount;

                    if (printParams != null && printParams.Count > 0) {
                        foreach (var item in printParams) {
                            //Reading Named Substrings,读取标签字段
                            if (btFormat.SubStrings.Any(p => p.Name == item.Key)) {
                                btFormat.SubStrings[item.Key].Value = item.Value;
                            }
                            //Print Label ,打印标签
                        }
                    }

                    LogManager.Debug($"执行打印开始,打印参数:{JsonConvert.SerializeObject(printParams)}");
                    Result result1 = btFormat.Print("RePrintBoxJob_" + qrCode);
                    LogManager.Debug($"执行打印完成,rls={result1.ToString()},打印参数:{JsonConvert.SerializeObject(printParams)}");

                    //Close Label Format ,关闭标签模板
                    btFormat.Close(SaveOptions.DoNotSaveChanges);

                    if (result1 == Result.Failure) {
                        throw new Exception($"打印失败");
                    }
                    if (result1 == Result.Timeout) {
                        throw new Exception($"打印超时，请检查！");
                    }
                    LogManager.Info($"PrinterLabel Dispose. printerName = {printerName}，printModePath = {template.TemplatePath}");
                }

                LogManager.Info($"PrinterLabel Dispose. printerName = {printerName}，printModePath = {template.TemplatePath}");

            });

            return true;
        }

        public string GenerateQrCode(TemplateEntity temp, Dictionary<string, string> inputParams, out string curIndex, out Dictionary<string, string> printParams, bool isAddIndex = true) {

            var tempParams = _mainDbOperate.GetModelList<ParamsEntity>(o => o.TemplateID == temp.Id).OrderBy(o => o.Sort).ToList();
            curIndex = string.Empty;
            printParams = new Dictionary<string, string>();
            StringBuilder qrCoderStr = new StringBuilder();

            if (temp != null && tempParams != null && tempParams.Count > 0) {

                foreach (var item in tempParams) {

                    if (item.ParamsType == Enums.eParamType.Dynamic) {
                        switch (item.ValueType.Value) {
                            case eValueType.Year:
                                item.Value = GetViewTableYear(item.ViewTableID);
                                break;
                            case eValueType.Moths:
                                item.Value = GetViewTableMoths(item.ViewTableID);
                                break;
                            case eValueType.Day:
                                item.Value = GetViewTableDay(item.ViewTableID);
                                break;
                            case eValueType.Index:
                                if (curIndex == "") {
                                    curIndex = GetViewTableIndex(temp.ProductID, item.Length, ePrintStartionCode.PG_12, isAddIndex);
                                }
                                item.Value = curIndex;
                                break;
                            case eValueType.Date:
                                item.Value = DateTime.Now.ToString("yyyyMMdd");
                                break;
                            case eValueType.Date2:
                                item.Value = DateTime.Now.ToString("yyyy-MM-dd");
                                break;
                            case eValueType.Date3:
                                item.Value = DateTime.Now.ToString("yyyy/MM/dd");
                                break;
                            case eValueType.Date4:
                                item.Value = DateTime.Now.ToString("yyMMdd");
                                break;
                            case eValueType.DateTime:
                                item.Value = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                                break;
                            case eValueType.DateTime2:
                                item.Value = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");
                                break;
                            case eValueType.Check:
                                item.Value = CodeCalculator.GetCheckCode(temp, printParams["BAR"]);
                                break;
                            default:
                                break;
                        }

                    } else if (item.ParamsType == eParamType.Input) {
                        if (inputParams != null && inputParams.Any(o => o.Key == item.ParamsKey)) {
                            item.Value = inputParams[item.ParamsKey];
                        }
                    }

                    if (item.IsTempParams) {
                        if (printParams.ContainsKey(item.ParamsKey)) {
                            var str = printParams[item.ParamsKey];
                            printParams[item.ParamsKey] = str + item.Value;
                        } else {
                            printParams.Add(item.ParamsKey, item.Value);
                        }
                    }

                    if (item.IsQrCodeField) {
                        qrCoderStr.Append(item.Value);
                    }
                }
            }
            if (qrCoderStr.ToString() == "") {
                qrCoderStr = new StringBuilder(printParams["BAR"].ToString());
            }
            printParams.Add("EWM_N1", qrCoderStr.ToString());
            return qrCoderStr.ToString();
        }


        #region Private

        private string GetViewTableYear(long viewTableID) {
            var viewTableDtls = _mainDbOperate.GetModelList<ViewTableDtlEntity>(o => o.ViewTabeID == viewTableID);
            var val = viewTableDtls.Where(o => o.OriginalValue == DateTime.Now.Year.ToString()).FirstOrDefault()?.TargetValue ?? "";
            return val;
        }

        private string GetViewTableMoths(long viewTableID) {
            var viewTableDtls = _mainDbOperate.GetModelList<ViewTableDtlEntity>(o => o.ViewTabeID == viewTableID);
            var val = viewTableDtls.Where(o => o.OriginalValue == DateTime.Now.Month.ToString()).FirstOrDefault()?.TargetValue ?? "";
            return val;
        }

        private string GetViewTableDay(long viewTableID) {
            var viewTableDtls = _mainDbOperate.GetModelList<ViewTableDtlEntity>(o => o.ViewTabeID == viewTableID);
            var val = viewTableDtls.Where(o => o.OriginalValue == DateTime.Now.Day.ToString()).FirstOrDefault()?.TargetValue ?? "";
            return val;
        }

        private string GetViewTableIndex(long productID, int length, ePrintStartionCode stationCode,bool isAddIndex = true) {

            lock (_lockObj) {
                var indexModel = _mainDbOperate.GetModel<IndexEntity>(o => o.ProductID == productID
                && o.StationCode == stationCode
                && o.CurentDate == DateTime.Now.ToString("yyyyMMdd")
                );
                int index = 0;
                if (indexModel != null) {
                    index = indexModel.CurentIndex;
                } else {
                    index = 1;
                    if (stationCode == ePrintStartionCode.Q_OP580_2) {
                        index = 5000 + index;
                    }
                    indexModel = new IndexEntity() {
                        CreateTime = DateTime.Now,
                        CurentDate = DateTime.Now.ToString("yyyyMMdd"),
                        CurentIndex = index,
                        ProductID = productID,
                        StationCode = stationCode
                    };
                }

                if (isAddIndex) {
                    indexModel.CurentIndex = index + 1;
                    _mainDbOperate.GetFreeSql().InsertOrUpdate<IndexEntity>().SetSource(indexModel).ExecuteAffrows();
                }

                return index.ToString($"D{length}");
            }

        }
        #endregion

    }

}
